package com.rfsp.mcp.service.interfaceclient;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.rfp.sm.utils.SM2Utils;
import com.rfsp.common.base.BaseService;
import com.rfsp.common.base.ResultVO;
import com.rfsp.common.util.*;
import com.rfsp.mcp.enums.TransCodeEnum;
import com.rfsp.mcp.feign.McpRelayFeign;
import com.rfsp.mcp.mapper.MCPWsKeyMapper;
import com.rfsp.mcp.mapper.PfmMapper;
import com.rfsp.mcp.mapper.WsItfMapper;
import com.rfsp.mcp.pojo.dto.FlowDTO;
import com.rfsp.mcp.pojo.dto.OrgDirectoryDto;
import com.rfsp.mcp.pojo.po.FlowPO;
import com.rfsp.mcp.pojo.po.OrgYbjPO;
import com.rfsp.mcp.pojo.po.PfmPO;
import com.rfsp.mcp.pojo.vo.*;
import com.rfsp.mcp.service.FlowService;
import com.rfsp.common.service.ParamService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.*;
@Service
public class WSOrgDirectoryService extends BaseService<OrgYbjPO> {

     public Logger logger = LoggerFactory.getLogger(WSOrgDirectoryService.class);

     @Autowired
     private PfmMapper pfmMapper;
     @Autowired
     private WsItfMapper wsItfMapper;

     @Autowired
     McpRelayFeign feign;
     @Autowired
     FlowService flowService;

     @Autowired
     ParamService paramService;

     @Value("${mcp.file-path-paylog}")
     private String filePath;

     @Autowired
     private MCPWsKeyMapper mCPWsKeyMapper;

     @Transactional
     public ResultVO<String> queryOrgDirectory(OrgDirectoryDto orgDirectoryDto){
          FlowDTO response_flow=new FlowDTO();
          //-----业务执行-----
          //1、通过医保平台ID，获取医保平台信息
          String pfmOrgCode = "";//医保平台统一社会信用代码
          String pfmName = "";//医保平台名称
          String edType = "";//加密类型：0表示不加密，1表示SM2加密
          String orgpub = "";//ORG_PUB对接系统加密公钥
          String plfpri = "";//PLF_PRI平台解密私钥
          String transCode = TransCodeEnum.M1001.getKey();//接口代码
          String msgId = UUID.randomUUID().toString();//流水号
     try{
          String sendDate = DateUtil.dateFormatStr("yyyyMMdd");//接口请求日期
          String sendTime = DateUtil.dateFormatStr("HHmmss");//接口请求时间
          if(orgDirectoryDto==null){
               return ResultVO.fail("orgDirectoryDto参数不能为空");
          }else if(orgDirectoryDto.getPfmId()==null){
               return ResultVO.fail("PfmId不能为空");
          }else if(orgDirectoryDto.getAid()==null){
               return ResultVO.fail("aid不能为空");
          }else{
               String aid = orgDirectoryDto.getAid();
               //需对aid进行解密
               //String priKeyFile = sqlMapper.selectOne("select t.para_value from M_DD_PARA t where t.para_code = 'MCP_M1001_PRIKEY'",String.class);
               String priKey = paramService.getValue("MCP_M1001_PRIKEY");
               aid = SM2Utils.decryptByKeyStr(aid, priKey);
               PfmPO p = new PfmPO();
               p.setId(orgDirectoryDto.getPfmId());
               p.setAid(aid);
               PfmPO pfmPO = pfmMapper.selectOne(p);
//               PfmPO pfmPO = pfmMapper.selectByPrimaryKey(orgDirectoryDto.getPfmId());
               if(pfmPO!=null){
                    pfmOrgCode = pfmPO.getPfmOrgCode();//医保系统的统一社会信用代码
                    pfmName = pfmPO.getPfmName();//医保平台名称
                    edType = pfmPO.getEdType();//加密类型：0表示不加密，1表示SM2加密
               }else{
                    return ResultVO.fail("PfmId参数值错误，请检查");
               }
          }
          log.error("edType==============================="+edType);
          //判断请求是否需要加密解密
          if(!StringUtils.isEmpty(edType)&&"1".equals(edType)){//如需要加密
               //如果需要加密,则获取对应的 公私钥
               Map<String, Object> wsKeyPara = new HashMap<String, Object>();
               wsKeyPara.put("fk_org_id", orgDirectoryDto.getPfmId());//医保局平台id
               List<Map<String, Object>> wsKeylist = mCPWsKeyMapper.getWsKey(wsKeyPara);
               if(null != wsKeylist && !wsKeylist.isEmpty()) {
                    Map<String, Object> map = wsKeylist.get(0);
                    orgpub = map.get("orgpub")==null?"":map.get("orgpub").toString();//ORG_PUB对接系统加密公钥
                    plfpri = map.get("plfpri")==null?"":map.get("plfpri").toString();//PLF_PRI平台解密私钥
                    if(StringUtils.isEmpty(orgpub)||StringUtils.isEmpty(plfpri)){
                         return ResultVO.fail("如需要SM2加密，对接系统加密公钥和平台解密私钥不能为空值，请检查");
                    }
               }else{
                    return ResultVO.fail("未查到该平台SM2加密信息，请检查");
               }
          }

          //组装json请求报文
          ObjectMapper objectMapper = new ObjectMapper();
          ObjectNode json = objectMapper.createObjectNode();
          json.put("pfmOrgCode", pfmOrgCode);
          json.put("transCode", transCode);
          json.put("msgId", msgId);
          json.put("sendDate", sendDate);
          json.put("sendTime", sendTime);
          json.put("mark1", "");
          json.put("mark2", "");
          json.put("mark3", "");
          // 转换为字符串
          String jsonString = json.toString();

          //2、获取接口配置管理中医保局平台URL和转发应用URL
          String forWordUrl = "";//转发程序URL
          URI baseUri = null;
          String pfmUrl = "";//医保局平台系统url
          String status = "";//接口状态
          Map<String, Object> para = new HashMap<String, Object>();
          para.put("org_id", orgDirectoryDto.getPfmId());
          para.put("code", TransCodeEnum.M1001.getKey());
          List<Map<String, Object>> list = wsItfMapper.getBizIdByItf(para);
          if(null != list && !list.isEmpty()){
               Map<String, Object> map = list.get(0);
               pfmUrl = map.get("uri")==null?"":map.get("uri").toString();//医保局平台URL
               if(StringUtils.isEmpty(pfmUrl)){
                    return ResultVO.fail("接口配置信息表中，医保局平台URL值为空");
               }
               forWordUrl = map.get("url")==null?"":map.get("url").toString();//转发系统URL
               if(StringUtils.isEmpty(forWordUrl)){
                    return ResultVO.fail("接口配置信息表中，转发系统URL值为空");
               }
               status = map.get("status")==null?"":map.get("status").toString();//接口状态
               if(StringUtils.isEmpty(status)){
                    return ResultVO.fail("接口配置信息表中，接口状态值为空");
               }else if(!"1".equals(status)){
                    return ResultVO.fail("接口配置信息表中，接口状态值为停用");
               }
               baseUri = new URI(forWordUrl);
          }else{
               return ResultVO.fail("没有接口配置信息");
          }

          //3、先生成一条请求流水数据信息和将请求报文json文件落地
          FlowDTO request_flow=new FlowDTO();
          request_flow.setAid(getAID());//辅助标识，防止修改主键ID查询的漏洞，不保证唯一
          request_flow.setCurrentNo(msgId);//请求流水号
          request_flow.setTransCode(TransCodeEnum.M1001.getKey());
          request_flow.setStatus("4");//处理成功
          request_flow.setInFlag("1");//请求方向 1：请求
          request_flow.setOrgNo(pfmOrgCode);//医保局平台组织机构代码
          request_flow.setOperation("0");//接口业务方向：0平台到医保系统
          request_flow.setPfmId(orgDirectoryDto.getPfmId());

          //以接口请求方向代码+请求流水号（唯一值）作为文件名
          String request_fileName=request_flow.getInFlag()+request_flow.getCurrentNo()+".txt";
          String request_filePath = this.filePath.replaceFirst("date/", StringUtil.dateToString(new Date(), "yyyy/MM/dd/"));
          request_flow.setContEncript(request_filePath+request_fileName);//文件路径+名称
          request_flow.setSdate(new Date());
          request_flow.setStime(new Date());
          request_flow.setEdate(new Date());
          request_flow.setEtime(new Date());
          //存储落地json文件
          FileUtil.create(request_filePath,request_fileName,jsonString,false);
          //保存接口流水表
          createFlow(request_flow);

          //4、调用转发服务进行查询，返回json报文
          List<OrgYbjDirectoryVO> lData = new ArrayList<>();

          //判断请求是否需要sm2加密解密
          McpInterfaceResultVO resultVO = null;
          if(!StringUtils.isEmpty(edType)&&"1".equals(edType)){
               resultVO = feign.queryOrgDirectory(baseUri,pfmUrl,jsonString,edType,orgpub,plfpri);
          }else{
               resultVO = feign.queryOrgDirectory(baseUri,pfmUrl,jsonString,edType,"","");
          }

          //5、插入响应信息接口流水和报文文件落地（成功或失败都需要插流水和落文件）

          response_flow.setAid(getAID());//辅助标识，防止修改主键ID查询的漏洞，不保证唯一
          response_flow.setCurrentNo(msgId);//请求流水号
          response_flow.setTransCode(TransCodeEnum.M1001.getKey());
          response_flow.setStatus("4");//处理成功
          response_flow.setInFlag("2");//请求方向 2:响应
          response_flow.setOrgNo(pfmOrgCode);//医保局平台组织机构代码
          response_flow.setOperation("1");//接口业务方向：1：医保系统到平台
          response_flow.setPfmId(orgDirectoryDto.getPfmId());

          ObjectMapper mapper = new ObjectMapper();
          String content="";
          try {
               content += mapper.writeValueAsString(resultVO);
          } catch (JsonProcessingException e) {
               logger.error(e.getMessage());
               e.printStackTrace();
          }
          content+="\n\n";
          //以接口响应方向+请求流水号（唯一值）作为文件名
          String response_fileName=response_flow.getInFlag()+response_flow.getCurrentNo()+".txt";
          String response_filePath = this.filePath.replaceFirst("date/", StringUtil.dateToString(new Date(), "yyyy/MM/dd/"));
          response_flow.setContEncript(response_filePath+response_fileName);//文件路径+名称
          response_flow.setSdate(new Date());
          response_flow.setStime(new Date());
          response_flow.setEdate(new Date());
          response_flow.setEtime(new Date());
          //存储落地json文件
          FileUtil.create(response_filePath,response_fileName,content,false);
          //保存接口流水表
          createFlow(response_flow);

          //6、----保存名录信息数据-----
          if(resultVO!=null&&resultVO.getMsg().equals("success")){
               //转发接口服务返回的报文数据
               String jsonResult = resultVO.getData();
               //判断返回的JSON是否包含数据
               if(!StringUtils.isEmpty(jsonResult)&&!JsonUtil.isEmptyJson(jsonResult)) {
                    lData = JsonUtil.toBeanList(jsonResult, OrgYbjDirectoryVO.class, "miOrgList");
                    //存储医保局定点机构信息表名录信息
                    StringBuffer errBuffer = new StringBuffer();//如存在存储失败的记录，记录失败原因，写入到json文件中，且置流水表状态为失败
                    if (lData != null && lData.size() > 0) {
                         for (OrgYbjDirectoryVO vo : lData) {
                              vo.setPfmId(orgDirectoryDto.getPfmId());
                              vo.setPfmName(pfmName);
                              mergeData(vo, orgDirectoryDto, errBuffer);
                         }
                    }

                    //判断是否有存储失败的记录
                    if (errBuffer.length() > 0) {
                         //1、变更流水表状态为失败
                         FlowPO queryPo = new FlowPO();
                         queryPo.setAid(response_flow.getAid());
                         queryPo.setPfmId(response_flow.getPfmId());
                         queryPo.setLogId(response_flow.getLogId());
                         List<FlowPO> listFlowPo = flowService.queryList(queryPo);
                         if (listFlowPo != null && listFlowPo.size() > 0) {
                              FlowPO po = listFlowPo.get(0);
                              po.setStatus("3");//处理失败
                              flowService.update(po);
                         }
                         //2、重写json文件，增加存储失败信息
                         ObjectMapper objectMapperAdd = new ObjectMapper();
                         File jsonFile = new File(response_flow.getContEncript());
                         try {
                              // 读取JSON文件到Map对象（或其他Java对象）
                              Map<String, Object> jsonMap = objectMapperAdd.readValue(jsonFile, Map.class);
                              // 修改Java对象（这里是Map）
                              jsonMap.put("isStoragefailed", "failed");
                              jsonMap.put("storagefailedMsg", errBuffer.toString());
                              // 将修改后的对象写回JSON文件
                              objectMapper.writeValue(jsonFile, jsonMap); // 或者使用Files工具类覆盖原文件内容，例如：Files.write(Paths.get("path/to/your/data.json"), objectMapper.writeValueAsBytes(jsonMap));
                         } catch (IOException e) {
                              e.printStackTrace();
                         }
                         //如果所有记录全存储失败，没有一条成功存储的，直接返回上层应用 处理失败
                         if (lData.size() == StringUtil.countSubstring(errBuffer.toString(), "||")) {
                              return ResultVO.fail("同步医保定点机构名录信息失败");
                         }

                    }
               }
               //-----如果全部存储成功，或者有部分信息存储成功的情况，向上层应用返回 执行成功-----
               return ResultVO.success("同步医保定点机构名录信息成功");

          }else{
               //请求医保局平台报文失败的，更新流水表信息为处理失败，异常内容就在落地的json文件中
               FlowPO queryPo=new FlowPO();
               queryPo.setAid(response_flow.getAid());
               queryPo.setPfmId(response_flow.getPfmId());
               queryPo.setLogId(response_flow.getLogId());
               List<FlowPO> listFlowPo = flowService.queryList(queryPo);
               if(listFlowPo!=null&&listFlowPo.size()>0){
                    FlowPO po = listFlowPo.get(0);
                    po.setStatus("3");//处理失败
                    flowService.update(po);
               }
               //向上层应用返回调用失败
               logger.error("=====转发应用调用医保局平台接口服务失败=====");
               return ResultVO.fail("转发应用调用医保局平台接口服务失败");
          }
     }catch (Exception e){
          //1、变更流水表状态为失败
          FlowPO queryPo = new FlowPO();
          queryPo.setAid(response_flow.getAid());
          queryPo.setPfmId(response_flow.getPfmId());
          queryPo.setLogId(response_flow.getLogId());
          List<FlowPO> listFlowPo = flowService.queryList(queryPo);
          if (listFlowPo != null && listFlowPo.size() > 0) {
               FlowPO po = listFlowPo.get(0);
               po.setStatus("3");//处理失败
               flowService.update(po);
          }
          e.printStackTrace();
          logger.error("=========同步医保定点机构名录信息失败:=============,{}",e);
          return ResultVO.fail("同步医保定点机构名录信息失败");
     }
}


     /**
      * 获取秘钥路径
      * @param url
      * @return
      */
     public static String getKeyPath(String url){

          String os = System.getProperty("os.name");
          if (os != null && os.startsWith("Windows")) {
               url = "d:"+url;
          }

          return url;
     }


     @Transactional
     public void mergeData(OrgYbjDirectoryVO vo,OrgDirectoryDto orgDirectoryDto,StringBuffer errBuffer) throws Exception{
     OrgYbjPO orgYbjPO = new OrgYbjPO();
     try{
          orgYbjPO = this.makePo(vo,orgDirectoryDto);
          //循环保存
          OrgYbjPO queryorgYbjPO = new OrgYbjPO();
          queryorgYbjPO.setPfmId(vo.getPfmId());
          queryorgYbjPO.setOrgNo(vo.getOrgNo());
          List<OrgYbjPO> list = this.queryList(queryorgYbjPO);
          if(list!=null&&list.size()>0){
               orgYbjPO.setId(list.get(0).getId());
               orgYbjPO.setUpdateTime(new Date());//变更时间
               orgYbjPO.setOptType("2");//操作类型（1.新增 2.修改 3.删除）
               orgYbjPO.setSource(vo.getPfmName());//信息来源 = 医保平台名称
               this.update(orgYbjPO);
          }else{
               orgYbjPO.setCreateTime(new Date());//创建时间
               orgYbjPO.setOptType("1");//操作类型（1.新增 2.修改 3.删除）
               orgYbjPO.setAid(getAID());//辅助标识，防止修改主键ID查询的漏洞，不保证唯一
               orgYbjPO.setSource(vo.getPfmName());//信息来源 = 医保平台名称
               this.save(orgYbjPO);
          }

     }catch (Exception e){
          //可以在这里记录错误日志，但不抛出异常，允许事务继续
          logger.error("=========医保定点机构名录信息存储失败:=============,{}",e);
          //如果某条记录存储失败，则记录在json文件中
          errBuffer.append(e.getMessage()).append("||");
     }




}

     private Integer createFlow(FlowDTO dto){
     Integer count=flowService.create(dto);
     return count;
}
     public String getAID() {
     String str = "1234567890qwertyuiopasdfghjklzxcvbnm";
     Random r = new Random();

     StringBuffer sb = new StringBuffer(16);

     for(int i=0;i<16;i++) {
          int index = r.nextInt(str.length());
          sb.append(str.charAt(index));
     }
     return sb.toString();
}

     public OrgYbjPO makePo(OrgYbjDirectoryVO vo,OrgDirectoryDto orgDirectoryDto) throws Exception {
          OrgYbjPO orgYbjPO = new OrgYbjPO();
       try{

          if(StringUtils.isEmpty(vo.getOrgNo())){
               throw new Exception("医疗机构代码值不能为空");
          }else{
               orgYbjPO.setOrgNo(vo.getOrgNo());//医疗机构代码(必填项)
          }
            if(StringUtils.isEmpty(vo.getOrgName())){
                 throw new Exception("医疗机构名称值不能为空");
            }else{
                 orgYbjPO.setOrgName(vo.getOrgName());//医疗机构名称（必填项）
            }

          orgYbjPO.setOrgCode(vo.getOrgCode());//统一社会信用代码

            if(StringUtils.isEmpty(vo.getValidFlag())){
                 throw new Exception("定点机构有效性值不能为空");
            }else{
                 orgYbjPO.setValidFlag(vo.getValidFlag());//定点机构有效性（必填项）
            }

          orgYbjPO.setRemark1(vo.getRemark1());//预留字段1
          orgYbjPO.setRemark2(vo.getRemark2());//预留字段2
          orgYbjPO.setRemark3(vo.getRemark3());//预留字段3
          orgYbjPO.setRemark4(vo.getRemark4());//预留字段4
          orgYbjPO.setRemark5(vo.getRemark5());//预留字段5
          orgYbjPO.setRemark6(vo.getRemark6());//预留字段6
          orgYbjPO.setRemark7(vo.getRemark7());//预留字段7
          orgYbjPO.setRemark8(vo.getRemark8());//预留字段8
          orgYbjPO.setRemark9(vo.getRemark9());//预留字段9
          orgYbjPO.setRemark10(vo.getRemark10());//预留字段10
          //copy完，再补充其他字段项
          orgYbjPO.setPfmId(vo.getPfmId());//医保平台ID
          //orgYbjPO.setSource(vo.getPfmName());//信息来源 = 医保平台名称
          //orgYbjPO.setAid(getAID());//辅助标识，防止修改主键ID查询的漏洞，不保证唯一
          orgYbjPO.setOptTime(new Date());//操作时间
          orgYbjPO.setOptUserId(orgDirectoryDto.getOptUserId());//操作用户ID
     }catch (Exception e){
            logger.error("=========makePo响应报文中存在属性值格式转换异常，请检查:=============,{}",e);
            throw new Exception("响应报文中存在属性值格式转换异常，请检查："+e.getMessage());
     }

          //return orgYbjPO;
          return XssUtils.replaceXss(orgYbjPO);

     }

}
